"use strict";

var toolkit = require("./toolkit");
const NUMS = toolkit.NUMS;

class CheckerInteral {
    constructor(matrix) {
        this.matrix = matrix;
        this.marks = toolkit.makeMatrix(true);
    }

    check() {
        return this.checkRows().checkCols().checkBlocks();
    }

    checkRows() {
        let marks = this.marks;
        this.matrix.forEach(function(row, rowIndex) {
            for (var i = 0; i < 9; i++) {
                if (!row[i]) {
                    marks[rowIndex][i] = false;
                    continue;
                }
                var start = i;
                while ((start = row.indexOf(row[i], start + 1)) > 0) {
                    marks[rowIndex][i] = false;
                    marks[rowIndex][start] = false;
                }
            }
        });
        return this;
    }

    checkCols() {
        let marks = this.marks;
        let matrix = this.matrix;
        NUMS.map(function(n, rowIndex) {
            var col = new Array(9);
            for (var i = 0; i < 9; i++) {
                col[i] = matrix[i][rowIndex]
            }
            return col;
        }).forEach(function(col, colIndex) {
            for (var i = 0; i < 8; i++) {
                if (!col[i]) {
                    continue;
                }
                var start = i;
                while ((start = col.indexOf(col[i], start + 1)) > 0) {
                    marks[i][colIndex] = false;
                    marks[start][colIndex] = false;
                }
            }
        });
        return this;
    }

    checkBlocks() {
        let marks = this.marks;
        let matrix = this.matrix;
        NUMS.forEach(function(n, blockIndex) {
            var block = toolkit.getBlock(matrix, blockIndex);
            for (var i = 0; i < 8; i++) {
                if (!block[i]) {
                    continue;
                }
                
                let start = i;
                let coor;
                while ((start = block.indexOf(block[i], start + 1)) > 0) {
                    let coor = toolkit.convertFromBlockCell(blockIndex, i);
                    marks[coor.rowIndex][coor.colIndex] = false;
                    let another = toolkit.convertFromBlockCell(blockIndex, start);
                    marks[another.rowIndex][another.colIndex] = false;
                }
            }
        });
        return this;
    }
}

const __ = "__";

class Checker {
    static check(matrix) {
        var checker = new Checker(matrix)
        checker.check();
        return checker;
    }

    constructor(matrix) {
        this[__] = new CheckerInteral(matrix);
    }

    get marks() {
        return this[__].marks;
    }

    get isSuccess() {
        return this.marks.every(function(row) {
            return row.every(function(v) {
                return v;
            });
        });
    }

    check() {
        return this[__].check().marks;
    }
    
    print() {
        toolkit.print(this.marks, function(v) {
            return v ? "_" : "F";
        });
        return this;
    }
}

module.exports = Checker;
